#include <buola/media/codec/bffmpegencoder.h>

#include "coutputcontext.h"
#include "coutputaudiostream.h"
#include "coutputvideostream.h"

#include <buola/utility/placeholders.h>
#include <buola/iterator/indirect.h>

namespace buola { namespace media {

BFfmpegEncoder::BFfmpegEncoder()
    :   BBox("ffmpeg encoder")
    ,   oData(this,"data in")
{
}

BFfmpegEncoder::~BFfmpegEncoder()
{

}

void BFfmpegEncoder::SetFormat(const std::string &pFormat)
{
    mFormat=pFormat;
}

void BFfmpegEncoder::AddAudioStream(const std::string &pCodec)
{
    SAudio *lAudio=new SAudio;
    
    lAudio->mCodec=pCodec;
    lAudio->iAudio=new blackbox::CStreamIn<int16_t>(this,"audio in "+to_string(iAudio.size()+1));
    iAudio.push_back(lAudio->iAudio);
    
    mAudio.emplace_back(lAudio);
}

void BFfmpegEncoder::AddVideoStream(const std::string &pCodec,const CSize_i &pSize)
{
    SVideo *lVideo=new SVideo;
    
    lVideo->mCodec=pCodec;
    lVideo->mSize=pSize;
    lVideo->iVideo=new blackbox::CDataIn<img::CImage_rgb8>(this,"video in "+to_string(iVideo.size()+1));
    iVideo.push_back(lVideo->iVideo);
    lVideo->kVideo=new blackbox::CClockIn(this,"video clock "+to_string(kVideo.size()+1),
                                 std::bind(&BFfmpegEncoder::ClockCB,this,kVideo.size()));
    kVideo.push_back(lVideo->kVideo);

    mVideo.emplace_back(lVideo);
}

void BFfmpegEncoder::ClockCB(int i)
{
    msg_info() << "clock called\n";

    SVideo *lVideo=mVideo[i].get();
    
    AVPacket *lPacket=lVideo->mStream->EncodeImage(lVideo->iVideo->Get());
    
    if(lPacket)
    {
        mCtx->WriteInterleaved(lPacket);
        delete lPacket;
    }
}

void BFfmpegEncoder::DoInitialize()
{
    ffmpeg::init_ffmpeg();
}

void BFfmpegEncoder::DoActivate()
{
    mCtx.reset(new ffmpeg::COutputContext(mFormat));
    mCtx->Open(oData);

    for(SAudio &lAudio : indirect_range(mAudio))
    {
        lAudio.mStream.reset(mCtx->NewAudioStream(lAudio.mCodec));
    }
    
    for(SVideo &lVideo : indirect_range(mVideo))
    {
        lVideo.mStream.reset(mCtx->NewVideoStream(lVideo.mCodec,lVideo.mSize));
    }

    mCtx->WriteHeader();
}

/*namespace blackbox*/ } /*namespace buola*/ }
